package controller;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Set;
import java.util.logging.Logger;

import model.BusinessTypes;
import model.MailingManager;

import com.google.appengine.api.datastore.Email;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.PhoneNumber;
import com.google.appengine.api.datastore.Text;

import dataBase.Ad;
import dataBase.AllBiz;
import dataBase.Business;
import dataBase.Client;
import dataBase.Colors;
import dataBase.ConnectToDataBase;
import dataBase.Order;
import dataBase.Status;
import sharedServlets.*;

public class Controller {

	private static Controller singleton = new Controller();
	private ConnectToDataBase database;
	private MailingManager mailingManager;

	private Controller() {
		// TODO Auto-generated constructor stub
		database = ConnectToDataBase.getInst();
		mailingManager = MailingManager.getInst();
	}

	public static Controller getInstance()
	{
		return singleton;
	}

	public int newBisAccount(String bizName,String bizType, String bizNum, byte[] logoPic,PhoneNumber phoneNumber,Email email,String website,String userName,
			String password,ArrayList<String> statusList,ArrayList<Double> EtaList, ArrayList<String> messages,
			String background, String secBackground, String borderColor, String skypeLogin)
	{
		int result = database.newBisAccount(bizName,bizType, bizNum, logoPic, phoneNumber, email,website, userName, password,statusList, EtaList, messages,
				background, secBackground,  borderColor,skypeLogin);

		if (result==0)
			mailingManager.greetingMailBiz(userName,password,email.getEmail());
		return result;

	}

	public int updateBisAccount(String bizName,String bizType, String bizNum, byte[] logoPic,PhoneNumber phoneNumber,Email email,String website, String userName,
			String password,ArrayList<String> statusList,ArrayList<Double> EtaList, ArrayList<String> messages,
			String background, String secBackground, String borderColor, String skype, Long[] orderUrgencyTime)
	{
		return database.updateBisAccount(bizName,bizType, bizNum, logoPic, phoneNumber, email,website, userName, password,statusList, EtaList, messages,
				background, secBackground,  borderColor,skype, orderUrgencyTime);

	}

	public int newClientAccount(String userName,String password,PhoneNumber phoneNumber,Email email){
		int result = database.newClientAccount(userName, password, phoneNumber, email);
		if (result == 0)
			mailingManager.greetingMailClient(userName,password,email.getEmail());
		return result;
	}

	public int updateClientAccount(String userName,String password,PhoneNumber phoneNumber,Email email){
		return database.updateClientAccount(userName, password, phoneNumber, email);
	}


	public Business getBiz(String userName)
	{
		return database.getBiz(userName);
	}

	public int newOrder(int orderID,int currentStatus,Text comments,String address,String userNameBiz , PhoneNumber phone, Email email, boolean sendMail,String details,Integer orderUrgency){
		int result = database.newOrder(orderID, currentStatus, comments, address, userNameBiz, phone,email,sendMail,details,orderUrgency);
				
		Logger.getLogger("newOrderBusiness").warning("Result is: "+result);
		if (result==0)
		{
			//will check if we already send mail to the email that the biz add
			boolean isEmailAlreadyExist = false;

			List<Client> clients = database.getClientsByPhone(phone);
			for (Client client: clients)
			{
				if (client.getEmail().getEmail().equals(email.getEmail()))
					isEmailAlreadyExist=true;

				Logger.getLogger("newOrderBusiness").warning("Send notification");
				mailingManager.newOrderMail(userNameBiz,orderID,client.getUserName(),details,address,phone.getNumber(),client.getEmail().getEmail(),false,getBiz(userNameBiz).getLogoPic());
				Logger.getLogger("newOrderBusiness").warning("Client id: "+client.getRegistId());
				if(client.getRegistId()!=null)
					C2DM.getInst().sendMessage(client.getRegistId(),"New Message From: "+AllBiz.getInst().userNameToBizName(userNameBiz), "New Order", "Order Num: "+orderID+" from: "+AllBiz.getInst().userNameToBizName(userNameBiz), ConnectToDataBase.getInst().getOrder(orderID, userNameBiz));					
				
				Logger.getLogger("newOrderBusiness").warning("After Send notification");

			}

			//send also to the email that the biz added
			if (sendMail && (!email.getEmail().equals("")) && (!isEmailAlreadyExist))
			{
				mailingManager.newOrderMail(userNameBiz,orderID,"",details,address,phone.getNumber(),email.getEmail(),true,getBiz(userNameBiz).getLogoPic());					
			}
			
			
		}

		return result;

	}

	public int BizlogIn(String userName,String password){
		return database.BizlogIn(userName, password);
	}

	public int ClientlogIn(String userName,String password){
		return database.ClientlogIn(userName, password);
	}

	public boolean ClientExist(String userName) {
		return database.ClientExist(userName);
	}

	public Order getOrder(int orderNum,String userNameBiz){
		return database.getOrder(orderNum, userNameBiz);
	}

	public  List<Order> getOrdersOfBiz(String userName)
	{
		return database.getOrdersofBiz(userName);
	}

	public  int updateOrderActive(int orderNum,String bizUserName,boolean isActive)
	{
		sendC2DMMessageFromOrder(orderNum, bizUserName, "Order was completed by "+AllBiz.getInst().userNameToBizName(bizUserName), "Order Num: "+orderNum);
		return database.updateOrderActive(orderNum,bizUserName,isActive);
	}

	public  List<Order> getAvailableOrdersOfBiz(String userName)
	{
		return database.getAvailableOrdersOfBiz(userName);
	}
	public  List<Order> getNotAvailableOrdersOfBiz(Business biz)
	{
		return database.getNotAvailableOrdersOfBiz(biz);
	}
	public List<Status> getStatusesOfBiz(String userName){
		return database.getStatusesOfBiz(userName);
	}

	public String getCurrentStatusOfOrder(Order order){
		//		Key key = order.getLevelsList().get(order.getLevelsList().size()-1);
		//		return database.getStatusName(key);
		return database.getCurrentStatusOfOrder(order);
	}

	public int changeLevelInOrder(String userNameBiz,int orderNum, int newLevelNum){
		int result = database.changeLevelInOrder(userNameBiz, orderNum, newLevelNum);
		sendC2DMMessageFromOrder(orderNum, userNameBiz, "Status was changed", "Order Num: "+orderNum+" from: "+AllBiz.getInst().userNameToBizName(userNameBiz));
		return result;
	}

	public  List<Order> getOrdersByPhone(PhoneNumber phone)	{
		return database.getOrdersByPhone(phone);		
	}

	public List<Order> getClientOrders(String userName)
	{
		return database.getClientOrders(userName);
	}

	public Client getClient(String userName)
	{
		return database.getClient(userName);
	}

	public List<String> statusOfOrder(Order order)
	{
		return database.statusOfOrder(order);		
	}

	public int addOrderToClient(String userNameClient, String bizUserName, int orderID, String phone,boolean statusNotification, boolean messageNotification)
	{

		return database.addOrderToClient(userNameClient, bizUserName, orderID, phone, statusNotification, messageNotification);
	}

	public int sendMessage(String bizUserName, int orderID, Text text) {
		sendC2DMMessageFromOrder(orderID, bizUserName, "New message from "+AllBiz.getInst().userNameToBizName(bizUserName), "Order Num: "+orderID);
		return database.sendMessage(bizUserName, orderID, text);		
	}

	public byte[] retrieveImage(String userName) 
	{
		return database.retrieveImage(userName);
	}

	public int getNextFreeOrderId(String userNameBiz)
	{
		return database.getNextFreeOrderId(userNameBiz);
	}

	public Colors getColors(String userNameBiz)
	{
		return database.getColors(userNameBiz);
	}

	public LinkedHashMap<String, Integer> getStatusHash(String userNameBiz, Date from, Date to)
	{
		return database.getStatusHash(userNameBiz, from,to);
	}
	public ArrayList<HashMap<String, Integer>> getTotalOrders(String userNameBiz, Date from, Date to){
		return database.getTotalOrders(userNameBiz, from, to);
	}
	public int forgetPasswordBiz(String userNameBiz)
	{
		Business biz = database.getBiz(userNameBiz);
		if (biz==null)
			return 1;
		mailingManager.forgetPassword(biz.getUserName(),biz.getPassword(),biz.getEmail().getEmail());
		return 0;
	}

	public int forgetPasswordClient(String userNameClient)
	{
		Client c = database.getClient(userNameClient);
		if (c==null)
			return 1;
		mailingManager.forgetPassword(c.getUserName(),c.getPassword(),c.getEmail().getEmail());
		return 0;
	}

	public ArrayList<String> allBizNameArray()
	{
		//
		return AllBiz.getInst().allBizNameArray();
	}

	public ArrayList<String> allBizUserNameArray()
	{
		return AllBiz.getInst().allBizUserNameArray();
	}

	public String bizNameToUserName(String bizName)
	{
		return AllBiz.getInst().bizNameToUserName(bizName);
	}

	public String userNameToBizName(String bizUserName)
	{
		return AllBiz.getInst().userNameToBizName(bizUserName);
	}

	public ArrayList<String> getStatusOfBizType(String bizType,String langName)
	{
		return BusinessTypes.getInst().getStatusOfBizType(bizType,langName);		 
	}

	public ArrayList<String> getMessageOfBizType(String bizType, String langName)
	{
		return BusinessTypes.getInst().getMessageOfBizType(bizType,langName);
	}
	public int setMessageToRead(int orderID,String userNameBiz,boolean newMessageToRead)
	{
		return database.setMessageToRead(orderID,userNameBiz,newMessageToRead);
	}

	public int orderSettingClient(String userNameBiz,int orderID, boolean statusNotification, boolean messageNotification) {
		return database.orderSettingClient(userNameBiz, orderID, statusNotification, messageNotification);
	}

	public int orderSettingBusiness(int orderID, Text comments, String destAddress,
			String userNameBiz, PhoneNumber newPhone, Email email,
			boolean sendMailBoolean, String details, Integer orderUrgency) {
		return database.orderSettingBusiness(orderID, comments, destAddress, userNameBiz, newPhone, email, sendMailBoolean, details, orderUrgency);
	}

	public int cancelSendToOrderMail(int orderID,String userNameBiz)
	{
		return database.cancelSendToOrderMail(orderID, userNameBiz);		
	}

	public int addBizAd(String bizUserName, byte[] imageBytes,String link) {
		return database.addBizAd(bizUserName,imageBytes,link);
	}

	public int deleteAdBusiness(String bizUserName, int id) {
		return database.deleteAdBusiness(bizUserName,id);
	}

	public ArrayList<LinkedHashMap<String, Double>> timesStatistic(String bizUserName,Date from, Date to)
	{
		return database.timesStatistic(bizUserName, from, to);
	}

	public int deleteOrder(String userName, int orderID) {
		return database.deleteOrder(userName,orderID);

	}
	public Ad getRandomAdByClient(String clientUserName)
	{
		return database.getRandomAdByClient(clientUserName);
	}

	public Business keyToBusiness(long id)
	{
		return database.keyToBusiness(id);
	}
	public Business keyToBusiness(String id)
	{
		if(id==null)
			return null;
		long key = 0;
		try{
			key = Long.parseLong(id);
		}
		catch (Exception e) {
			return null;
		}
		return database.keyToBusiness(key);
	}
	public Ad keyToAd(long id)
	{
		return database.keyToAd(id);
	}
	public Order keyToOrder(long id)
	{
		return database.keyToOrder(id);
	}
	public long bizNameToKeyID(String bizName)
	{
		return AllBiz.getInst().bizNameToKeyID(bizName);
	}


	public int register(String userName, String registrationId) {
		return database.register(userName,registrationId);
		
	}

	public int unregister(String userName) {
		return database.unregister(userName);
		
	}

	public String adClicked(long AdKey){
		String webSite = database.adClicked(AdKey);
		if(webSite!=null)
			return webSite;
		else
			return getSyncaWebAddress();
	}

	public void adAppeared(long id) {
		database.adAppeared(id);
		
	}
	
	
	public int sendC2DMMessageFromOrder(int orderNum,String userNameBiz,String title,String message){
		Order order = getOrder(orderNum, userNameBiz);
		Logger.getLogger("changeStatusBusiness").warning("Order: "+order);
		return sendC2DMMessageFromOrder(order,title,message);
	}
	
	public int sendC2DMMessageFromOrder(Order order,String title,String message){
		if(order==null)
			return 1;
		
		List<Key> clientKeyList = order.getClientList();
		
		System.out.println("c2dm client list "+clientKeyList);
		if(clientKeyList==null)
			return 1;
		Logger.getLogger("changeStatusBusiness").warning("list: "+clientKeyList.size());

		List<Client> clientList = database.keyToClient(clientKeyList);
		if(clientList==null)
			return 1;
		List<Client> clientList2 = database.getClientsByPhone(order.getPhoneNumber());
		if(clientList2==null)
			return 1;
		Logger.getLogger("changeStatusBusiness").warning("client list: "+clientList2.size());

		for(Client client : clientList2){
			Logger.getLogger("changeStatusBusiness").warning("Client: "+client.getUserName());
			if(client.getRegistId()!=null){
				Logger.getLogger("changeStatusBusiness").warning("Client id: "+client.getRegistId());
				C2DM.getInst().sendMessage(client.getRegistId(), "New Message From: "+AllBiz.getInst().userNameToBizName(order.getBusinessUserName()), title, message, order);
			}
		}
		return 0;
	}
	public void addVote(String userNameBiz, int orderID, int vote){
		database.addVote(userNameBiz, orderID, vote);
	}
	
	public List<Ad> getAdsCount(String userNameBiz){
		return database.getAdsCount(userNameBiz);
	}
	
	public HashMap<String, Integer> getTotalOrdersByPriority(Business Biz, Date from, Date to)
		{
			return database.getTotalOrdersByPriority(Biz, from, to);
		}
	public String getSyncaWebAddress()
	{
		//return "http://localhost:8888";
		return "http://syncahoratest.appspot.com";
	}
	



}
